--[[ scheme_type: active_section author: Alundaio modified_by: Auto-generated point_jobs around smart_terrain bound campfires for gulag_general --]] -- TODO: Fix use_camp. It spams animations. use_camp manually set = false in add_to_binder. -- Need to make it independent of sr_camp.script so that it doesn't require space_restrictors evaid = 17000 actid = 17000 local used_vids = {} ------------------------------------------------------------------------------------ local alife, vector, level, mrand = alife, vector, level, math.random ------------------------------------------------------------------------------------ local assoc_tbl = { idle = {director = {"sit"}, listener = {"sit","sit_ass","sit_knee","sit_ass_weapon","sit_ass_eat_bread","sit_ass_drink_vodka","sit_ass_drink_energy","sit_ass_eat_kolbasa"}}, harmonica = {director = {"play_harmonica"}, listener = {"sit","sit_ass","sit_knee","sit_ass_weapon","sit_ass_eat_bread","sit_ass_drink_vodka","sit_ass_drink_energy","sit_ass_eat_kolbasa"}}, guitar = {director = {"play_guitar"}, listener = {"sit","sit_ass","sit_knee","sit_ass_weapon","sit_ass_eat_bread","sit_ass_drink_vodka","sit_ass_drink_energy","sit_ass_eat_kolbasa"}}, story = {director = {"sit"}, listener = {"sit","sit_ass","sit_knee","sit_ass_weapon","sit_ass_eat_bread","sit_ass_drink_vodka","sit_ass_drink_energy","sit_ass_eat_kolbasa"}}, } -----------------------------Private----------------- local function get_rand_vertex(npc,vo,minD,maxD) local dir = vector():set(npc:position()):sub(vo:position()) dir = vector_rotate_y(dir,mrand(360)) return vo:vertex_in_direction(vo:level_vertex_id(),dir,mrand(minD,maxD)) end ----------------------------------------------------- class "evaluator_need_job" (property_evaluator) function evaluator_need_job:__init(storage, name) super(nil, name) self.st = storage end function evaluator_need_job:evaluate() return xr_logic.is_active(self.object, self.st) or false end ---------------------------------------------------------------------------------------------------------------------- class "action_point_campfire" (action_base) function action_point_campfire:__init (npc_name, action_name, storage) super(nil, action_name) self.st = storage self.st.approved_actions = {"play_harmonica","play_guitar","sit","sit_ass","sit_knee","sit_ass_weapon","sit_ass_eat_bread","sit_ass_drink_vodka","sit_ass_drink_energy","sit_ass_eat_kolbasa" } end function action_point_campfire:initialize() action_base.initialize(self) self.object:set_desired_position() self.object:set_desired_direction() self.object:set_path_type(game_object.level_path) end function action_point_campfire:activate_scheme() local vid,look if (self.st.smart) then local fires = db.campfire_table_by_smart_names[self.st.smart] if (fires and not is_empty(fires)) then local campfire local t = {} local function create_campfire_point(pos,dir) local radius = 8 local vertex_id = 4294967295 local tmp_pos = VEC_ZERO while (vertex_id >= 4294967295) do tmp_pos.x = pos.x + dir.x * radius tmp_pos.z = pos.z + dir.z * radius tmp_pos.y = pos.y vertex_id = level.vertex_id(tmp_pos) if (vertex_id >= 4294967295 or used_vids[vertex_id]) then if (radius > 1) then radius = radius - 1 else break end end end return vertex_id end for id,binder in pairs(fires) do if (binder.object) then local dir = vector():set(binder.object:direction()) local pos = binder.object:position() t[#t+1] = pos for i=1,6 do vid = create_campfire_point(pos,vector_rotate_y(dir,i*60)) look = pos if (vid and vid < 4294967295 and not used_vids[vid]) then break end end end if (vid and vid < 4294967295 and not used_vids[vid]) then break end end -- fallback no camp or all space is taken if (vid == nil or vid >= 4294967295 or used_vids[vid]) then local pos = t and #t > 0 and t[math.random(#t)] or self.object:position() vid = utils_obj.find_random_cover(self.object,pos,5,15) look = pos end end end -- fallback if no campfires if (vid == nil or vid >= 4294967295 or used_vids[vid]) then local smart = self.st.smart and SIMBOARD:get_smart_by_name(self.st.smart) or xr_gulag.get_npc_smart(self.object) local pos = smart and smart.position or self.object:position() vid = utils_obj.find_random_cover(self.object,pos,5,15) look = pos end self.st.signals = {} self.st.look_position = look self.st.vid = utils_obj.send_to_nearest_accessible_vertex(self.object,vid or self.object:level_vertex_id()) state_mgr.set_state(self.object,xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.reach_movement)) used_vids[self.st.vid] = true end function action_point_campfire:execute() action_base.execute(self) if not (self.st.vid) then return end local npc = self.object if not (npc:level_vertex_id() == self.st.vid) then if (npc:path_type() ~= game_object.level_path) then npc:set_path_type(game_object.level_path) end self.st.vid = utils_obj.send_to_nearest_accessible_vertex(npc,self.st.vid,"xr_campfire_point") state_mgr.set_state(npc,xr_logic.pick_section_from_condlist(db.actor, npc, self.st.reach_movement)) return end local state = state_mgr.get_state(self.object) local camp = sr_camp.get_current_camp(npc:position()) if (camp) then if (self.st.use_camp == true and state ~= "sleep" and state ~= "sleep_sit") then self.st.camp = camp camp:register_npc(npc:id()) self.in_camp = true elseif (self.st.use_camp ~= true or state == "sleep" or state == "sleep_sit") then if (self.in_camp) then camp:unregister_npc(npc:id()) self.in_camp = nil self.st.camp = nil end end elseif (self.in_camp == true and not self.st.camp) then self.st.camp:unregister_npc(npc:id()) self.in_camp = nil self.st.camp = nil end if (self.st.camp) then if (self.st.use_camp ~= true or state == "sleep" or state == "sleep_sit") then self.st.camp:unregister_npc(npc:id()) end elseif (self.st.use_camp and state ~= "sleep" and state ~= "sleep_sit" and not self.st.camp_checked) then self.st.camp_checked = true local camp = sr_camp.get_current_camp(npc:position()) if (camp) then self.st.camp = camp camp:register_npc(npc:id()) end end local tg = time_global() if (not self.st.camp and self.st.sound_idle) then self.st.__sound_idle = self.st.__sound_idle or tg + mrand(10000,30000) if (tg > self.st.__sound_idle) then xr_sound.set_sound_play(self.object:id(), self.st.sound_idle) self.st.__sound_idle = nil end end local anm = self:get_camp_action() or xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.anm) state_mgr.set_state(self.object, anm, nil, nil, {look_position = self.st.look_position}) end function action_point_campfire:get_camp_action() if not (self.st.camp) then return end local camp_action, is_director = self.st.camp:get_camp_action(self.object:id()) if not (camp_action) then return end if (self.current_action and self.current_action ~= "play_guitar" and self.current_action ~= "play_harmonica") then self.__dtimer = not self.__dtimer and time_global() + math.random(10000,15000) or self.__dtimer if (time_global() < self.__dtimer) then return end end local role = is_director and "director" or "listener" local tbl = assoc_tbl[camp_action][role] self.current_action = tbl and tbl[mrand(#tbl)] or "sit_ass" return self.current_action end function action_point_campfire:finalize() action_base.finalize(self) if (self.st.camp) then self.st.camp:unregister_npc(self.object:id()) end self.st.camp_checked = nil if (self.st.vid) then used_vids[self.st.vid] = nil end end function action_point_campfire:position_riched() return self.cover_position:distance_to_sqr(self.object:position()) <= 0.4 end ---------------------------------------------------------------------------------------------------------------------- -- binder ---------------------------------------------------------------------------------------------------------------------- function set_scheme(npc, ini, scheme, section, gulag_name) local st = xr_logic.assign_storage_and_bind(npc, ini, "campfire_point", section,temp) st.logic = xr_logic.cfg_get_switch_conditions(ini, section, npc) st.sound_idle= ini:r_string_ex(section,"sound_idle") st.smart = ini:r_string_ex(section,"smart") st.anm = xr_logic.parse_condlist(npc, "anim", "anim", ini:r_string_ex(section,"anim") or "hide") st.reach_movement = xr_logic.parse_condlist(npc, "reach_movement", "reach_movement", ini:r_string_ex(section,"reach_movement") or "patrol") local use_camp = xr_logic.parse_condlist(npc, "use_camp", "use_camp", ini:r_string_ex(section,"use_camp") or "true") st.use_camp = xr_logic.pick_section_from_condlist(db.actor, npc, use_camp) == "true" end function add_to_binder(npc,ini,scheme,section,storage) if not npc then return end local wp = world_property local manager = npc:motivation_action_manager() if not manager then return end local evaluator = evaluator_need_job(storage, "need_cover") local action = action_point_campfire(npc, "action_point_campfire", storage) if not evaluator or not action then return end manager:add_evaluator(evaid,evaluator) action:add_precondition( wp(evaid,true) ) action:add_effect( wp(evaid,false) ) action:add_effect( wp(xr_evaluators_id.state_mgr + 4, false) ) manager:add_action(actid,action) xr_logic.subscribe_action_for_events(npc, storage, action) action:add_precondition( wp(stalker_ids.property_alive,true) ) action:add_precondition( wp(stalker_ids.property_danger,false) ) action:add_precondition( wp(stalker_ids.property_enemy,false) ) action:add_precondition( wp(xr_evaluators_id.sidor_wounded_base,false) ) --printf("ACTION_ALIFE_ID(xr_campfire_point.add_to_binder): " .. tostring(xr_actions_id.alife)) action = manager:action(xr_actions_id.alife) if not evaluator or not action then return end action:add_precondition( wp(evaid, false) ) action = manager:action(xr_actions_id.state_mgr + 2) action:add_precondition( wp(evaid, false) ) end